package com.rdxer.service;

import com.rdxer.core.utils.dbutils.BeanUtils;
import com.rdxer.core.utils.dbutils.CRUDUtlis;
import com.rdxer.core.utils.IdWorker;
import com.rdxer.core.exception.exceptions.BadRequestException;
import com.rdxer.core.exception.exceptions.BaseException;
import org.springframework.data.jpa.repository.JpaRepository;

import java.io.Serializable;
import java.util.List;
import java.util.Optional;

public interface CRUDServiceInterface<T, ID extends Serializable> {

    public JpaRepository<T, ID> getRepository();


    IdWorker getIdWorker();

    default T findById(ID id) {
        Optional<T> r = getRepository().findById(id);
        if (r.isEmpty()) {
            throw BaseException.ofNotFound();
        }
        return r.get();
    }

    default void delete(ID id) {
        boolean b = getRepository().existsById(id);
        if (b == false) {
            throw BaseException.ofNotFound();
        }
        getRepository().deleteById(id);
    }

    // reset id to null
    default T addAndResetIdToNull(T model) {
        modelSetId(null, model);
        return getRepository().saveAndFlush(model);
    }

    default T add(T model) {

       setModelDefaultId(model);

        return getRepository().save(model);
    }

    default boolean existsById(ID id) {
        return getRepository().existsById(id);
    }

    ////////////////  save
    default T save(T model) {
        ID id = modelGetId(model);
        if (id == null){
            return add(model);
        }
        return getRepository().save(model);
    }
    ///////////////////   update

    default T update(T model) {
        if (modelGetId(model) == null) {
            throw new BadRequestException();
        }
        return update_exec(model);
    }

    default T update(ID id, T model) {
        if (modelGetId(model) != null && modelGetId(model) != id) {
            throw BaseException.ofBadRequest();
        }
        modelSetId(id, model);
        return update_exec(model);
    }

    /**
     * 支持部分更新
     *
     * @param id
     * @param model
     * @return
     */
    default T updateOfPatch(ID id, T model) {

        if (modelGetId(model) != null && modelGetId(model) != id) {
            throw BaseException.ofBadRequest();
        }

        Optional<T> r = getRepository().findById(id);

        if (r.isEmpty()) {
            throw BaseException.ofNotFound();
        }

        modelSetId(id, model);

        //支持部分更新
        String[] nullPropertyNames = BeanUtils.getNullPropertyNames(model);
        org.springframework.beans.BeanUtils.copyProperties(model, r.get(), nullPropertyNames);

        return update_exec(r.get());
    }

    default T update_exec(T model) {
        T save = getRepository().save(model);
        return save;
    }


    //////////////////////////////////////   id  opertion

    default ID modelGetId(T model) {
        return CRUDUtlis.getId(model);
    }

    default void modelSetId(ID id, T model) {
        CRUDUtlis.setId(id, model);
    }
    default void setModelDefaultIdIfNeed(T model) {
        ID id = modelGetId(model);
        if (id == null){
            setModelDefaultId(model);
        }
    }

    default void setModelDefaultId(T model) {
        ID l;
        Class idFieldClass = CRUDUtlis.findIdFieldClass(model);
        if (String.class.isAssignableFrom(idFieldClass)){
            l  = (ID) getIdWorker().nextIdHex();
        }else {
            l  = (ID) Long.valueOf(getIdWorker().nextId());
        }

        modelSetId(l, model);
    }
    //////////////////////  list

    /**
     * 查询全部列表
     *
     * @return
     */
    default List<T> findAll() {
        return getRepository().findAll();
    }


    default void deleteByIds(List<ID> ids) {
        for (ID id : ids) {
//            getRepository().deleteById(id);
            delete(id);
        }
    }
}

